/*
 * @Date: 2023-03-15 19:48:00
 * @LastEditTime: 2023-10-08 15:46:20

 * 介绍:
 */
import Web3 from "web3";
import {
  abi,
  abiUniswapV2Router,
  abiFactory,
  abiLp,
  abiWk,
} from "./abi/ethAbi";
import {
  parseAmount,
  parseBalance,
  SdkRes,
  sdkSucceed,
  sdkFail,
} from "./index";
import PubSub from "pubsub-js";
import { sdk } from "@@/enum/pubsub";
import type { TransactionReceipt, Transaction } from "web3-eth";
import { funDelay } from "@@/utils/tools/function";
import dayjs from "dayjs";

function callWeb3() {
  const nodeUrl = import.meta.env.VITE_ETH_CALL_NODE;
  return new Web3(nodeUrl || (window.ethereum as any));
}
function sendWeb3() {
  const nodeUrl = import.meta.env.VITE_ETH_SEND_NODE;
  return new Web3(nodeUrl || (window.ethereum as any));
}

function plusSendWeb3() {
  const nodeUrl = import.meta.env.VITE_ETH_PLUS_SEND_NODE;
  if (nodeUrl) return new Web3(nodeUrl);
  return sendWeb3();
}
function plusCallWeb3() {
  const nodeUrl = import.meta.env.VITE_ETH_PLUS_CALL_NODE;
  if (nodeUrl) return new Web3(nodeUrl);
  return callWeb3();
}
/**判断是不是 Ethereum平台 */
export function sdkIsEthereum() {
  return Boolean(window.ethereum);
}

/**
 * * 获取GasPrice
 */
export function getGasPrice() {
  return new Promise<string | void>((resolve) => {
    const web3 = callWeb3();
    web3.eth
      .getGasPrice()
      .then((res) => {
        resolve(res);
      })
      .catch(() => {
        resolve();
      });
  });
}
/**
 * * 调整GasPrice
 * @param multiply 乘
 * @returns
 */
export async function adjustGasPrice(multiply: number = 3) {
  const res = await getGasPrice();
  if (!res) return "";
  return String(Math.floor(Number(res) * multiply));
}

/**开启用户切换监听 */
window.ethereum?.on("accountsChanged", (e: string[]) => {
  console.log("on切换用户", e);
  PubSub.publishSync(sdk.relogin);
  PubSub.publishSync(sdk.userChange, e);
});
window.ethereum?.on("chainChanged", (e: StrNumber) => {
  console.log("on切换链", e);
  PubSub.publishSync(sdk.relogin);
  PubSub.publishSync(sdk.chainChange, e);
});

/**获取当前钱包地址 */
export function sdkGetAddress() {
  const message = "获取当前钱包地址";
  return new Promise<string | undefined>((resolve) => {
    callWeb3()
      .eth.getAccounts()
      .then((res) => {
        res.push(window.ethereum?.selectedAddress);
        console.log(message, res);
        resolve(res[0]);
      })
      .catch((err) => {
        console.error(message, err);
        resolve(undefined);
      });
  });
}

/**连接钱包 */
export function sdkConnect() {
  return new Promise<SdkRes<string>>((resolve) => {
    const message = "连接钱包";
    try {
      console.log(message);
      if (!window.ethereum)
        return resolve(sdkFail("请切换以太坊钱包环境后重试!"));
      window.ethereum
        .request({
          method: "eth_requestAccounts",
        })
        .then(async (res: string[]) => {
          resolve(sdkSucceed(message, res[0]));
        })
        .catch((error: Error) => {
          console.error(message);
          resolve(sdkFail(error.message, error));
        });
    } catch (error: any) {
      console.error(message);
      resolve(sdkFail(error.message, error));
    }
  });
}

/**
 * * 获取当前网络版号
 * @returns
 */
export function sdkGetChainId() {
  return new Promise<SdkRes<StrNumber>>((resolve) => {
    const message = "获取网络版号";
    try {
      console.log(message);
      // window
      //   .ethereum!.request({ method: "eth_chainId" })
      //   .then((chainId: string) => {
      //     resolve(
      //       sdkSucceed(parseInt(Number(chainId).toString(), 10).toString())
      //     );
      //   })
      callWeb3()
        ?.eth.getChainId()
        .then((res) => {
          resolve(sdkSucceed(message, res));
        })
        .catch((error: any) => {
          console.error(message);
          resolve(sdkFail(error.message, error));
        });
    } catch (error: any) {
      console.error(message);
      resolve(sdkFail(error.message, error));
    }
  });
}

/**
 * * 批准
 * @param mint 批准合约地址
 * @param amount 支付金额
 * @param format 精度
 * @param toAddress 批准地址
 * @param fromAddress 付款用户地址
 * @returns
 */
export function sdkApprove(
  mint: string,
  amount: number,
  format: number,
  toAddress: string,
  fromAddress?: string
) {
  return new Promise<SdkRes<string>>(async (resolve) => {
    const message = "批准";
    try {
      const vlaue = parseAmount(amount, format);
      fromAddress ??= await sdkGetAddress();
      console.log(message);
      console.log("amount", amount);
      console.log("format", format);
      console.log("vlaue", vlaue);
      console.log("toAddress", toAddress);
      console.log("fromAddress", fromAddress);
      if (!fromAddress) return resolve(sdkFail("获取当前用户地址失败"));
      const gasPrice = await adjustGasPrice();
      console.log("gasPrice", gasPrice);
      const web3 = sendWeb3();
      const contract = new web3.eth.Contract(abi as any, mint);
      const encodeABI = contract.methods
        .approve(toAddress, web3.utils.toHex(vlaue))
        .encodeABI()
        .substring(2);
      let tx = {
        from: fromAddress,
        to: mint,
        gasPrice,
        gas: "210000",
        data: encodeABI,
      };
      window
        .ethereum!.request({
          method: "eth_sendTransaction",
          params: [tx],
          from: fromAddress,
        })
        .then((res: string) => {
          resolve(sdkSucceed(message, res));
        })
        .catch((error: any) => {
          console.error(message);
          resolve(sdkFail(error.message, error));
        });
    } catch (error: any) {
      console.error(message);
      resolve(sdkFail(error.message, error));
    }
  });
}

/**
 * * 发起代币转账
 * @param mint 合约地址
 * @param amount 付款金额
 * @param format 精度
 * @param toAddress 收款地址
 * @param fromAddress 付款地址
 */
export function sdkTransferToken(
  mint: string,
  amount: number,
  format: number,
  toAddress: string,
  fromAddress?: string
) {
  return new Promise<SdkRes<string>>(async (resolve) => {
    const message = "代币转账";
    try {
      const value = parseAmount(amount, format);
      fromAddress ??= await sdkGetAddress();
      if (!fromAddress) return resolve(sdkFail("获取当前用户地址失败"));
      console.log(message);
      console.log("amount", amount, "format", format, "value", value);
      console.log("mint", mint);
      console.log("toAddress", toAddress);
      console.log("fromAddress", fromAddress);
      const gasPrice = await adjustGasPrice();
      console.log("gasPrice", gasPrice);
      const web3 = sendWeb3();
      const contract = new web3.eth.Contract(abi as any, mint);
      contract.methods
        .transfer(toAddress, value)
        .send({
          from: fromAddress,
          gas: "210000",
          gasPrice,
        })
        .then((res: any) => {
          console.log(message, res);
          resolve(sdkSucceed(message, res.transactionHash));
        })
        .catch((error: any) => {
          console.error(message);
          resolve(sdkFail(error.message, error));
        });
    } catch (error: any) {
      console.error(message);
      resolve(sdkFail(error.message, error));
    }
  });
}

/**
 * * 发起主币转账
 * @param amount 转账金额
 * @param format 精度
 * @param toAddress 收款方地址
 * @param fromAddress 付款方地址
 * @returns
 */
export function sdkTransfer(
  amount: number,
  format: number,
  toAddress: string,
  fromAddress?: string
) {
  return new Promise<SdkRes<string>>(async (resolve) => {
    const message = "主币转账";
    try {
      const value = parseAmount(amount, format);
      fromAddress ??= await sdkGetAddress();
      if (!fromAddress) return resolve(sdkFail("获取当前用户地址失败"));
      console.log(message);
      console.log("amount", amount, "format", format, "value", value);
      console.log("toAddress", toAddress);
      console.log("fromAddress", fromAddress);
      const gasPrice = await adjustGasPrice();
      console.log("gasPrice", gasPrice);
      sendWeb3()
        .eth.sendTransaction({
          to: toAddress,
          from: fromAddress,
          value: value,
          gas: "210000",
          gasPrice: gasPrice as any,
        })
        .then((res) => {
          console.log(message, res);
          resolve(sdkSucceed(message, res.transactionHash));
        })
        .catch((error) => {
          console.error(message);
          resolve(sdkFail(error.message, error));
        });
    } catch (error: any) {
      console.error(message);
      resolve(sdkFail(error.message, error));
    }
  });
}

/**
 * * 自动区分发起转账
 * @param mint 合约地址
 * @param amount 付款金额
 * @param format 精度
 * @param toAddress 收款地址
 * @param fromAddress 付款地址
 */
export function sdkAutoTransfer(
  mint: string | undefined | null,
  amount: number,
  format: number,
  toAddress: string,
  fromAddress?: string
) {
  if (mint)
    return sdkTransferToken(mint, amount, format, toAddress, fromAddress);
  return sdkTransfer(amount, format, toAddress, fromAddress);
}

/**
 * * 查询主币余额
 * @param format 精度
 * @param findAddress 持有用户地址
 * @returns
 */
export function sdkFindBalance(format: number, findAddress?: string) {
  return new Promise<SdkRes<string>>(async (resolve) => {
    const message = "查询主币余额";
    console.log(message);
    findAddress ??= await sdkGetAddress();
    if (!findAddress) return resolve(sdkFail("获取当前用户地址失败"));
    callWeb3()
      .eth.getBalance(findAddress)
      .then((res) => {
        resolve(sdkSucceed(message, parseBalance(res, format)));
      })
      .catch((error) => {
        console.error(message);
        resolve(sdkSucceed(error.message, error));
      });
  });
}

/**
 * * 查询代币余额
 * @param mint 合约地址
 * @param format 精度
 * @param findAddress 持有用户地址
 * @returns
 */
export function sdkFindTokenBalance(
  mint: string,
  format: number,
  findAddress?: string
) {
  return new Promise<SdkRes<string>>(async (resolve) => {
    const message = "查询代币余额";

    findAddress ??= await sdkGetAddress();
    if (!findAddress) return resolve(sdkFail("获取当前用户地址失败"));
    console.log(message);
    console.log("mint", mint);
    console.log("findAddress", findAddress);
    const web3 = callWeb3();
    const tokenContract = new web3.eth.Contract(abi as any, mint);
    tokenContract.methods
      .balanceOf(findAddress)
      .call()
      .then((res: any) => {
        console.log(res);

        resolve(sdkSucceed(message, parseBalance(res, format)));
      })
      .catch((error: any) => {
        console.error(message);
        resolve(sdkFail(error.message, error));
      });
  });
}

/**
 * * 自动区分查询主币代币余额
 * @param mint 合约地址
 * @param format 精度
 * @param findAddress 持有用户地址
 * @returns
 */
export function sdkAutoFindBalance(
  mint: string | undefined | null,
  format: number,
  findAddress?: string
) {
  if (mint) return sdkFindTokenBalance(mint, format, findAddress);
  return sdkFindBalance(format, findAddress);
}
/**
 * * 切换网络
 * @param chainId 链id
 * @returns
 */
export function sdkChangeChain(chainId: number) {
  return new Promise<SdkRes<any>>((resolve) => {
    const message = "切换网络";
    console.log(message);

    if (!window.ethereum)
      return resolve(sdkFail("请切换以太坊钱包环境后重试!"));
    window.ethereum
      .request({
        method: "wallet_switchEthereumChain",
        params: [
          {
            chainId: `0x${chainId.toString(16)}`,
          },
        ],
      })
      .then((res: any) => {
        resolve(sdkSucceed(message, res));
      })
      .catch((error: any) => {
        console.error(message);
        resolve(sdkFail(error.message, error));
      });
  });
}
/**
 * * 查询批准金额
 * @param mint 合约地址
 * @param format 精度
 * @param toAddress 批准给谁？受益地址
 * @param fromAddress 来自谁？支付者地址
 * @returns
 */
export function sdkFindApprove(
  mint: string,
  format: number,
  toAddress: string,
  fromAddress?: string
) {
  return new Promise<SdkRes<string>>(async (resolve) => {
    const web3 = plusCallWeb3();
    const contract = new web3.eth.Contract(abi as any, mint);
    const message = "查询已批准金额";
    console.log(message);
    fromAddress ??= await sdkGetAddress();
    contract.methods
      .allowance(fromAddress, toAddress)
      .call()
      .then((res: number) => {
        resolve(sdkSucceed(message, parseBalance(res, format)));
      })
      .catch((error: any) => {
        console.error(message);
        resolve(sdkFail(error.message, error));
      });
  });
}

/**
 * * 评估，预计兑换接收代币数量,接收to发送
 * @param amount 接收币种数量
 * @param tokenPath 合约地址对
 * @param tokenPath 币种精度对
 * @param address 兑换合约地址,一般为批准地址
 * @returns
 */
export function sdkEvaluationSwapFrom(
  amount: StrNumber,
  tokenPath: [string, string],
  formats: [number, number],
  address: string
) {
  return new Promise<SdkRes<string>>((resolve) => {
    const message = "评估兑换swapFrom接收数量";
    console.log(message);
    console.log("amount", amount);
    console.log("tokenPath", tokenPath);
    console.log("formats", formats);
    if (Number(amount) <= 0) return resolve(sdkSucceed(message, "0"));
    const web3 = callWeb3();
    const contract = new web3.eth.Contract(abiUniswapV2Router as any, address);
    const value = parseAmount(amount, formats[1]);
    console.log("value", value);

    if (tokenPath[0] == tokenPath[1])
      return resolve(sdkSucceed(message, String(amount)));

    contract.methods
      .getAmountsIn(value, tokenPath)
      .call()
      .then((res: [string, string]) => {
        console.log(message, res);
        resolve(sdkSucceed(message, parseBalance(res[0], formats[0])));
      })
      .catch((error: any) => {
        console.error(message);
        resolve(sdkFail(error.message, error));
      });
  });
}

/**
 * * 评估，预计兑换接收代币数量,接收to发送
 * @param amount 接收币种数量
 * @param tokenPath 合约地址对
 * @param tokenPath 币种精度对
 * @param address 兑换合约地址,一般为批准地址
 * @returns
 */
export function sdkEvaluationSwapTo(
  amount: StrNumber,
  tokenPath: [string, string],
  formats: [number, number],
  address: string
) {
  return new Promise<SdkRes<string>>((resolve) => {
    const message = "评估兑换swapTo发送数量";
    console.log(message);
    console.log("amount", amount);
    console.log("tokenPath", tokenPath);
    console.log("formats", formats);
    if (Number(amount) <= 0) return resolve(sdkSucceed(message, "0"));
    const web3 = callWeb3();
    const contract = new web3.eth.Contract(abiUniswapV2Router as any, address);
    const value = parseAmount(amount, formats[0]);
    console.log("value", value);
    if (tokenPath[0] == tokenPath[1])
      return resolve(sdkSucceed(message, String(amount)));

    contract.methods
      .getAmountsOut(value, tokenPath)
      .call()
      .then((res: [string, string]) => {
        console.log(message, res);
        resolve(sdkSucceed(message, parseBalance(res[1], formats[1])));
      })
      .catch((error: any) => {
        console.error(message);
        resolve(sdkFail(error.message, error));
      });
  });
}

/**
 *
 * @param amount 兑换数量
 * @param format 精度
 * @param tokenPath [fromCoinAddress,toCoinAddress]
 * @param address 兑换合约地址,一般为批准地址
 * @param toMin 接收最小数量
 * @param toFormat toMin精度
 * @param fromAddress 来自谁
 * @returns
 */
export function sdkSwap(
  amount: StrNumber,
  format: number,
  tokenPath: [string, string],
  address: string,
  toMin?: StrNumber,
  toFormat?: number,
  fromAddress?: string
) {
  return new Promise<SdkRes<string>>(async (resolve) => {
    const message = "代币兑换";
    try {
      console.log(message);
      fromAddress ??= await sdkGetAddress();
      if (!fromAddress) return resolve(sdkFail("获取当前用户地址失败"));
      const value = parseAmount(amount, format);
      const web3 = sendWeb3();
      const contract = new web3.eth.Contract(
        abiUniswapV2Router as any,
        address
      );
      console.log("amount", amount);
      console.log("value", value);
      console.log("tokenPath", tokenPath);
      console.log("fromAddress", fromAddress);
      const gasPrice = await adjustGasPrice();
      console.log("gasPrice", gasPrice);
      console.log("toMin", toMin);
      const toMinValue = parseAmount(toMin || 0, toFormat || 0);
      console.log("toMinValue", toMinValue);

      contract.methods
        // .swapExactTokensForTokens(
        .swapExactTokensForTokensSupportingFeeOnTransferTokens(
          value,
          toMinValue,
          tokenPath,
          fromAddress,
          dayjs().add(53, "year").unix()
        )
        .send({
          from: fromAddress,
          gas: "210000",
          gasPrice,
        })
        .then((res: TransactionReceipt) => {
          console.log(message, res);
          resolve(sdkSucceed(message, res.transactionHash));
        })
        .catch((error: any) => {
          console.error(message);
          resolve(sdkFail(error.message, error));
        });
    } catch (error: any) {
      console.error(message);
      resolve(sdkFail(error.message, error));
    }
  });
}

/**
 * * 获取币种精度
 * @param address 地址
 * @returns
 */
export function sdkDecimal(address: string) {
  return new Promise<SdkRes<number>>((resolve) => {
    const message = "查询币种精度";
    const web3 = callWeb3();
    const contract = new web3.eth.Contract(abi as any, address);
    contract.methods
      .decimals()
      .call()
      .then((res: number) => {
        resolve(sdkSucceed(message, res));
      })
      .catch((error: Error) => {
        console.error(message);
        resolve(sdkFail(error.message, error));
      });
  });
}

/**
 * * 轮询查询交易状态 info:0为超时
 * @param txid 交易哈希
 * @param time 重试间隔
 * @param count 重试次数
 * @param step 当前是第几次
 * @returns
 */
export function sdkFindTxid(
  txid: string,
  time: StrNumber = 3000,
  count: number = 20,
  step: number = 1
) {
  const message = `查询交易状态${step}/${count}`;
  console.log(message, txid);
  return new Promise<SdkRes<TransactionReceipt, 0 | Error>>((resolve) => {
    if (step > count) return resolve(sdkFail("轮询交易达到最大限度", 0));
    step++;
    const web3 = callWeb3();
    web3.eth.getTransactionReceipt(
      txid,
      async (error, res: TransactionReceipt | null) => {
        if (error) return resolve(sdkFail(error.message, error));
        if (!res) return retry();
        if (res.status === true) return resolve(sdkSucceed(message, res));
        if (res.status === false) return resolve(sdkFail(message, error));
        return retry();
      }
    );

    async function retry() {
      return resolve(
        await funDelay(sdkFindTxid, [txid, time, count, step], Number(time))
      );
    }
  });
}

export interface FindTxidInfoRes extends Transaction {
  /**未处理精度的支付金额 */
  amountValue: StrNumber;
}
/**
 * * 轮询查询交易信息 info:0为超时
 * @param txid 交易哈希
 * @param time 重试间隔
 * @param count 重试次数
 * @param step 当前是第几次
 * @returns
 */
export function sdkFindTxidInfo(
  txid: string,
  time: StrNumber = 3000,
  count: number = 20,
  step: number = 1
) {
  const message = `查询交易信息${step}/${count}`;
  console.log(message, txid);
  return new Promise<SdkRes<FindTxidInfoRes, 0 | Error>>((resolve) => {
    if (step > count) return resolve(sdkFail("轮询交易达到最大限度", 0));
    step++;
    const web3 = callWeb3();
    web3.eth.getTransaction(txid, async (error, res: Transaction | null) => {
      if (error) return resolve(sdkFail(error.message, error));
      if (!res) return retry();
      const amountValue = parseInt(`0x${res.input.slice(10 + 64)}`);
      return resolve(sdkSucceed(message, { ...res, amountValue }));
    });

    async function retry() {
      return resolve(
        await funDelay(sdkFindTxidInfo, [txid, time, count, step], Number(time))
      );
    }
  });
}

/**
 * * 添加流动性
 * @param tokenPath [代币地址1,代币地址2]
 * @param amountArr [数量1,数量2]
 * @param formatArr [精度1,精度2]
 * @param address 合约地址,一般为授权地址
 * @param toAddress 获益人地址，默认自己
 * @param fromAddress 发送人地址，默认自己
 * @returns
 */
export function sdkAddLiquidity(
  tokenPath: [string, string],
  amountArr: [StrNumber, StrNumber],
  formatArr: [number, number],
  address: string,
  toAddress?: string,
  fromAddress?: string
) {
  return new Promise<SdkRes<string>>(async (resolve) => {
    const message = "添加流动性";
    try {
      const _address = await sdkGetAddress();
      toAddress ??= _address;
      fromAddress ??= _address;
      if (!toAddress || !fromAddress)
        return resolve(sdkFail("获取当前用户地址失败"));
      const valueArr = [
        parseAmount(amountArr[0], formatArr[0]),
        parseAmount(amountArr[1], formatArr[1]),
      ];
      console.log(message);
      console.log("tokenPath", tokenPath);
      console.log("valueArr", valueArr);
      console.log("address", address);
      console.log("toAddress", toAddress);
      console.log("fromAddress", fromAddress);
      const gasPrice = await adjustGasPrice();
      console.log("gasPrice", gasPrice);

      const web3 = plusSendWeb3();
      const contract = new web3.eth.Contract(
        abiUniswapV2Router as any,
        address
      );

      contract.methods
        .addLiquidity(...tokenPath, ...valueArr, 0, 0, toAddress, 9999999999999)
        .send({
          from: fromAddress,
          gasPrice,
          gas: "250000",
        })
        .then((res: TransactionReceipt) => {
          console.log(message, res);
          resolve(sdkSucceed(message, res.transactionHash));
        })
        .catch((error: Error) => {
          console.error(message);
          resolve(sdkFail(error.message, error));
        });
    } catch (error: any) {
      console.error(message);
      resolve(sdkFail(error.message, error));
    }
  });
}

/**
 * * 解除流动性
 * @param tokenPath [代币地址1,代币地址2]
 * @param value 已进行精度处理的数量
 * @param address 合约地址，一般为授权地址
 * @param toAddress 获益人地址，默认自己
 * @param fromAddress 发送人地址，默认自己
 * @returns
 */
export function sdkRemoveLiquidity(
  tokenPath: [string, string],
  value: StrNumber,
  address: string,
  toAddress?: string,
  fromAddress?: string
) {
  return new Promise<SdkRes<string>>(async (resolve) => {
    const message = "解除流动性";
    try {
      const _address = await sdkGetAddress();
      toAddress ??= _address;
      fromAddress ??= _address;
      if (!toAddress || !fromAddress)
        return resolve(sdkFail("获取当前用户地址失败"));
      console.log(message);
      console.log("tokenPath", tokenPath);
      console.log("value", value);
      console.log("lpAddress", address);
      console.log("toAddress", toAddress);
      console.log("fromAddress", fromAddress);
      const gasPrice = await adjustGasPrice();
      console.log("gasPrice", gasPrice);

      const web3 = plusSendWeb3();
      const contract = new web3.eth.Contract(
        abiUniswapV2Router as any,
        address
      );
      contract.methods
        .removeLiquidity(...tokenPath, value, 0, 0, toAddress, 9999999999999)
        .send({
          from: fromAddress,
          gasPrice,
          gas: "300000",
        })
        .then((res: TransactionReceipt) => {
          console.log(message, res);
          resolve(sdkSucceed(message, res.transactionHash));
        })
        .catch((error: any) => {
          console.error(message);
          const err: TransactionReceipt = error;
          if (err.transactionHash && err.blockHash) {
            return resolve(sdkFail(`交易失敗，請調整手續費后再試`));
          }
          resolve(sdkFail(error.message, error));
        });
    } catch (error: any) {
      console.error(message);
      resolve(sdkFail(error.message, error));
    }
  });
}

/**
 * * 获取lp矿池地址
 * @param tokenPath [代币地址1,代币地址2]
 * @param address 合约地址
 * @returns
 */
export function sdkGetLpAddress(tokenPath: [string, string], address: string) {
  return new Promise<SdkRes<string>>((resolve) => {
    const message = "获取lp地址";
    const web3 = plusCallWeb3();
    const contract = new web3.eth.Contract(abiFactory as any, address);
    contract.methods
      .getPair(...tokenPath)
      .call()
      .then((res: string) => {
        resolve(sdkSucceed(message, res));
      })
      .catch((error: Error) => {
        console.error(message);
        resolve(sdkFail(error.message, error));
      });
  });
}

/**
 * * 获取lp矿池双币分别有多少
 * ! 该方法不会处理精度
 * @param address
 * @returns [未处理精度的余额1,未处理精度的余额2]
 */
export function sdkGetReserves(address: string) {
  return new Promise<SdkRes<[string, string]>>((resolve) => {
    const message = "lp矿池双币余额";
    const web3 = plusCallWeb3();
    const contract = new web3.eth.Contract(abiLp as any, address);
    contract.methods
      .getReserves()
      .call()
      .then((res: any) => {
        console.log(message, res);
        // * 返回两个字符串类型的数字
        resolve(sdkSucceed(message, [res._reserve0, res._reserve1]));
      })
      .catch((error: Error) => {
        console.error(message);
        resolve(sdkFail(error.message, error));
      });
  });
}

/**
 * * lp矿池索引0对应的币种合约
 * @param address
 */
export function sdkGetLpToken0(address: string) {
  return new Promise<SdkRes<string>>((resolve) => {
    const message = "lp矿池索引0对应的币种合约";
    console.log(message);
    console.log("address", address);
    const web3 = plusCallWeb3();
    const contract = new web3.eth.Contract(abiLp as any, address);
    contract.methods
      .token0()
      .call()
      .then((res: any) => {
        resolve(sdkSucceed(message, res));
      })
      .catch((error: Error) => {
        console.error(message);
        resolve(sdkFail(error.message, error));
      });
  });
}

/**
 * * 获取lp矿池总资产量
 * ! 该方法不会处理精度
 * @param address lp地址
 * @returns 未处理精度的lp矿池数量
 */
export function sdkLpTotalSupply(address: string) {
  return new Promise<SdkRes<string>>((resolve) => {
    const message = "lp矿池总资产量";
    console.log(message);
    const web3 = callWeb3();
    const contract = new web3.eth.Contract(abiLp as any, address);
    contract.methods
      .totalSupply()
      .call()
      .then((res: any) => {
        resolve(sdkSucceed(message, res));
      })
      .catch((error: Error) => {
        console.error(message);
        resolve(sdkFail(error.message, error));
      });
  });
}
/**
 * * 威客合约转账
 * @param contract_addr 合约地址
 * @param amount 数量
 * @param format 精度
 * @param toAddress 收款者地址
 * @param fromAddress 发起者地址
 * @returns
 */
export function sdkWkTransfer(
  contract_addr: string,
  amount: number,
  format: number,
  toAddress: string,
  fromAddress?: string
) {
  return new Promise<SdkRes<string>>(async (resolve) => {
    const message = "威客转账合约";
    try {
      fromAddress = await sdkGetAddress();
      console.log(message);
      if (!fromAddress) return resolve(sdkFail("获取当前用户地址失败"));
      const value = parseAmount(amount, format);
      console.log("contract_addr", contract_addr);
      console.log("fromAddress", fromAddress);
      console.log("amount", amount);
      console.log("format", format);
      console.log("value", value);
      const gasPrice = await adjustGasPrice();
      console.log("gasPrice", gasPrice);

      const web3 = plusSendWeb3();
      const contract = new web3.eth.Contract(abiWk as any, contract_addr);
      contract.methods
        .transfer(toAddress, value)
        .send({
          from: fromAddress,
          gasPrice,
          gas: "300000",
        })
        .then((res: TransactionReceipt) => {
          console.log(message, res);
          resolve(sdkSucceed(message, res.transactionHash));
        })
        .catch((error: any) => {
          console.error(message);
          const err: TransactionReceipt = error;
          if (err.transactionHash && err.blockHash) {
            return resolve(sdkFail(`交易失敗，請調整手續費后再試`));
          }
          resolve(sdkFail(error.message, error));
        });
    } catch (error: any) {
      console.error(message);
      resolve(sdkFail(error.message, error));
    }
  });
}

/**
 * * 获取lp矿池总资产量
 * ! 该方法不会处理精度
 * @param findAddress 自己的地址
 * @returns 未处理精度的lp矿池数量
 */
export function sdkWkLpInfo(contract_addr: string, findAddress?: string) {
  return new Promise<SdkRes<WkLpInfo>>(async (resolve) => {
    const message = "威客矿池信息";
    findAddress ??= await sdkGetAddress();
    console.log(message);
    if (!findAddress) return resolve(sdkFail("获取当前用户地址失败"));
    const web3 = callWeb3();
    const contract = new web3.eth.Contract(abiWk as any, contract_addr);
    contract.methods
      .poolInfo(findAddress)
      .call()
      .then((res: any) => {
        resolve(sdkSucceed(message, res));
      })
      .catch((error: Error) => {
        console.error(message);
        resolve(sdkFail(error.message, error));
      });
  });
}
export interface WkLpInfo {
  lpTotalSupply: string;
  lpBalance: string;
  usdtBalance: string;
  tokenBalance: string;
  tokenPrice: string;
  usdtAmount: string;
  tokenAmount: string;
}